<?php
/**
 * Pertyler DatabaseManagement
 * DatabaseModel
 * Table Classes
 *
 * @author	Emre Hasegeli <hasegeli@gmail.com>
 * @license	GNU General Public License v3
 */

namespace Pertyler;

require_once __DIR__ . '/main.php';

require_once __DIR__ . '/aTable.php';

class Table extends aTable
{
	public static function Select($id)
	{
		if(isset(self::$object[$id]))
			return self::$object[$id];

		$resultArray = Database::Get()->SelectResultArray('
SELECT "Table"."Schema",
		(SELECT id
				FROM pertyler."Table_Table"
				WHERE "Table"."BackgroundName" ~~ (regexp_replace(regexp_replace("BackgroundName",
						\'[_][0-9]+\',
						\'\'),
						\'.+[_]\',
						\'\') || \'\\\\_%\')) "ParentTable",
		"TableName"."Name",
		"TableName"."ShortName",
		"Table"."BackgroundName",
		"pg_fileClass".relname "FileTable",
		EXISTS(SELECT true
				FROM pg_catalog.pg_attribute
				WHERE attrelid = pg_class.oid
						AND attname = \'Unpublished\') "HasUnpublishedColumn",
		EXISTS(SELECT true
				FROM pg_catalog.pg_attribute
				WHERE attrelid = pg_class.oid
						AND attname = \'Language\') "HasLanguageColumn",
		EXISTS(SELECT true
				FROM information_schema.tables
				WHERE table_schema = "Table"."Schema"
						AND table_name = ((regexp_replace(regexp_replace("BackgroundName",
								\'[_][0-9]+\',
								\'\'),
								\'.+[_]\',
								\'\')) || \'_name\')) "HasNameTable",
		EXISTS(SELECT true
				FROM information_schema.columns
				WHERE table_schema = "Table"."Schema"
						AND table_name = ((regexp_replace(regexp_replace("BackgroundName",
								\'[_][0-9]+\',
								\'\'),
								\'.+[_]\',
								\'\')) || \'_name\')
						AND column_name = \'Alternative\') "HasNameTableAlternativeColumn"
	FROM pertyler."Table_Table" "Table"
		JOIN pg_catalog.pg_class ON pg_class.relname = "Table"."BackgroundName"
			JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
		JOIN pertyler."Table_name" "TableName" ON "Table".id = "TableName"."Table"
				AND "TableName"."Language" = ' . Role::Select()->DefaultLanguage()->Id() . '
		LEFT JOIN (SELECT pg_inherits.inhrelid,
					"pg_fileClass".relname
				FROM pg_catalog.pg_class "pg_fileClass"
					JOIN pg_catalog.pg_inherits ON pg_inherits.inhparent = "pg_fileClass".oid
				WHERE relname ~~* \'%file\'
						AND relnamespace = (SELECT oid
									FROM pg_catalog.pg_namespace
									WHERE nspname =  \'public\')) "pg_fileClass" ON "pg_fileClass".inhrelid = pg_class.oid
			WHERE "Table".id = ' . $id);

		if($resultArray)
			return new Table($resultArray['ParentTable'],
					$id,
					$resultArray['Name'],
					$resultArray['ShortName'],
					$resultArray['BackgroundName'],
					$resultArray['Schema'],
					$resultArray['HasNameTable'],
					$resultArray['HasNameTableAlternativeColumn'],
					$resultArray['HasLanguageColumn'],
					$resultArray['FileTable'],
					$resultArray['HasUnpublishedColumn']);
	}

	public static function SelectArray(Array $idArray)
	{
		$resultArrayArray = Database::Get()->SelectResultArrayArray('
SELECT "Table".id "Table",
		"Table"."Schema",
		(SELECT id
				FROM pertyler."Table_Table"
				WHERE "Table"."BackgroundName" ~~ (regexp_replace(regexp_replace("BackgroundName",
						\'[_][0-9]+\',
						\'\'),
						\'.+[_]\',
						\'\') || \'\\\\_%\')) "ParentTable",
		"TableName"."Name",
		"TableName"."ShortName",
		"Table"."BackgroundName",
		"pg_fileClass".relname "FileTable",
		EXISTS(SELECT true
				FROM pg_catalog.pg_attribute
				WHERE attrelid = pg_class.oid
						AND attname = \'Unpublished\') "HasUnpublishedColumn",
		EXISTS(SELECT true
				FROM pg_catalog.pg_attribute
				WHERE attrelid = pg_class.oid
						AND attname = \'Language\') "HasLanguageColumn",
		EXISTS(SELECT true
				FROM information_schema.tables
				WHERE table_schema = "Table"."Schema"
						AND table_name = ((regexp_replace(regexp_replace("BackgroundName",
								\'[_][0-9]+\',
								\'\'),
								\'.+[_]\',
								\'\')) || \'_name\')) "HasNameTable",
		EXISTS(SELECT true
				FROM information_schema.columns
				WHERE table_schema = "Table"."Schema"
						AND table_name = ((regexp_replace(regexp_replace("BackgroundName",
								\'[_][0-9]+\',
								\'\'),
								\'.+[_]\',
								\'\')) || \'_name\')
						AND column_name = \'Alternative\') "HasNameTableAlternativeColumn"
	FROM pertyler."Table_Table" "Table"
		JOIN pg_catalog.pg_class ON pg_class.relname = "Table"."BackgroundName"
			JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
		JOIN pertyler."Table_name" "TableName" ON "Table".id = "TableName"."Table"
				AND "TableName"."Language" = ' . Role::Select()->DefaultLanguage()->Id() . '
		LEFT JOIN (SELECT pg_inherits.inhrelid,
					"pg_fileClass".relname
				FROM pg_catalog.pg_class "pg_fileClass"
					JOIN pg_catalog.pg_inherits ON pg_inherits.inhparent = "pg_fileClass".oid
				WHERE relname ~~* \'%file\'
						AND relnamespace = (SELECT oid
									FROM pg_catalog.pg_namespace
									WHERE nspname =  \'public\')) "pg_fileClass" ON "pg_fileClass".inhrelid = pg_class.oid
	WHERE "Table".id IN ' . Database::Get()->SelectInput($idArray) . '
	ORDER BY "TableName"."Name"');

		if(!$resultArrayArray)
			return array();

		foreach($resultArrayArray AS $resultArray)
			if(isset(self::$object[$resultArray['Table']]))
				$array[$resultArray['Table']] = self::$object[$resultArray['Table']];
			else
				$array[$resultArray['Table']] = new self($resultArray['ParentTable'],
						$resultArray['Table'],
						$resultArray['Name'],
						$resultArray['ShortName'],
						$resultArray['BackgroundName'],
						$resultArray['Schema'],
						$resultArray['HasNameTable'],
						$resultArray['HasNameTableAlternativeColumn'],
						$resultArray['HasLanguageColumn'],
						$resultArray['FileTable'],
						$resultArray['HasUnpublishedColumn']);

		return $array;
	}

	public static function SelectTopLevelTableArray()
	{
		$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "TableIdArray"
	FROM "pertyler"."Table_Table"
	WHERE "BackgroundName" !~~ \'%\\\\_%\'');

		if($resultArray['TableIdArray'])
			return self::SelectArray($resultArray['TableIdArray']);

		return array();
	}

	public function SelectTableArray()
	{
		$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "TableIdArray"
	FROM "pertyler"."Table_Table"
	WHERE "BackgroundName" ~~ \'' . $this->UniqueName() . '\\\\_%\'');

		if($resultArray['TableIdArray'])
			return self::SelectArray($resultArray['TableIdArray']);

		return array();
	}

	public function SelectParentTable()
	{
		if($this->parent_id)
			return self::Select($this->parent_id);
	}

	public function SelectRelatedArray()
	{
		$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "TableIdArray"
	FROM pertyler."Table_Table"
	WHERE "BackgroundName" IN (SELECT relatedclass.relname
				FROM pg_catalog.pg_class
					JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
					JOIN pg_catalog.pg_constraint relatedconstraint ON relatedconstraint.confrelid = pg_class.oid
						JOIN pg_catalog.pg_class relatedclass ON relatedclass.oid = relatedconstraint.conrelid
						JOIN pg_attribute relatedattribute ON relatedattribute.attrelid = relatedconstraint.conrelid
								AND ARRAY[relatedattribute.attnum] = relatedconstraint.conkey
				WHERE pg_class.relkind IN (\'r\',
						\'v\')
						AND pg_namespace.nspname = \'' . $this->Schema() . '\'
						AND pg_class.relname = \'' . $this->baseName() . '\'
						AND (relatedclass.relname !~~ \'' . $this->UniqueName() . '%\'
								OR relatedattribute.attname != \'' . $this->UniqueName() . '\'))');

		if($resultArray['TableIdArray'])
			return self::SelectArray($resultArray['TableIdArray']);

		return array();
	}

	private function selectChildUnpublishedArray()
	{
		$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "TableIdArray"
	FROM pertyler."Table_Table" "Table"
		JOIN pg_catalog.pg_class ON pg_class.relname = "Table"."BackgroundName"
			JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
					AND pg_namespace.nspname = "Table"."Schema"
	WHERE "BackgroundName" ~~ \'' . $this->UniqueName() . '%\'
			AND pg_class.oid IN (SELECT attrelid
						FROM pg_attribute
						WHERE attname = \'Unpublished\')');

		if($resultArray['TableIdArray'])
			return self::SelectArray($resultArray['TableIdArray']);

		return array();
	}

	private function selectNullRelatedUnpublishedArray()
	{
		$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "TableIdArray"
	FROM pertyler."Table_Table"
	WHERE ("Schema",
			"BackgroundName") IN (SELECT relatedpg_namespace.nspname,
						relatedpg_class.relname
					FROM pg_catalog.pg_class
						JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
						JOIN pg_catalog.pg_constraint relatedpg_constraint ON relatedpg_constraint.confrelid = pg_class.oid
							JOIN pg_catalog.pg_class relatedpg_class ON relatedpg_class.oid = relatedpg_constraint.conrelid
							JOIN pg_attribute relatedpg_attribute ON relatedpg_attribute.attrelid = relatedpg_constraint.conrelid
									AND ARRAY[relatedpg_attribute.attnum] = relatedpg_constraint.conkey
					WHERE pg_class.relkind IN (\'r\',
							\'v\')
							AND pg_namespace.nspname = \'' . $this->Schema() . '\'
							AND pg_class.relname = \'' . $this->baseName() . '\'
							AND (relatedpg_class.relname !~~ \'' . $this->UniqueName() . '%\'
									OR relatedpg_attribute.attname != \'' . $this->UniqueName() . '\'))
							AND relatedpg_class.oid IN (SELECT attrelid
										FROM pg_attribute
										WHERE attname = \'Unpublished\')
							AND relatedpg_attribute.attnotnull = false');

		if($resultArray['TableIdArray'])
			return self::SelectArray($resultArray['TableIdArray']);

		return array();
	}

	private function selectNotNullRelatedUnpublishedArray()
	{
		$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "TableIdArray"
	FROM pertyler."Table_Table"
	WHERE ("Schema",
			"BackgroundName") IN (SELECT relatedpg_namespace.nspname,
						relatedpg_class.relname
					FROM pg_catalog.pg_class
						JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
						JOIN pg_catalog.pg_constraint relatedpg_constraint ON relatedpg_constraint.confrelid = pg_class.oid
							JOIN pg_catalog.pg_class relatedpg_class ON relatedpg_class.oid = relatedpg_constraint.conrelid
							JOIN pg_attribute relatedpg_attribute ON relatedpg_attribute.attrelid = relatedpg_constraint.conrelid
									AND ARRAY[relatedpg_attribute.attnum] = relatedpg_constraint.conkey
					WHERE pg_class.relkind IN (\'r\',
							\'v\')
							AND pg_namespace.nspname = \'' . $this->Schema() . '\'
							AND pg_class.relname = \'' . $this->baseName() . '\'
							AND (relatedpg_class.relname !~~ \'' . $this->UniqueName() . '%\'
									OR relatedpg_attribute.attname != \'' . $this->UniqueName() . '\'))
							AND relatedpg_class.oid IN (SELECT attrelid
										FROM pg_attribute
										WHERE attname = \'Unpublished\')
							AND relatedpg_attribute.attnotnull = true');

		if($resultArray['TableIdArray'])
			return self::SelectArray($resultArray['TableIdArray']);

		return array();
	}

	private $firstColumn;

	public function SelectFirstColumn()
	{
		if(isset($this->firstColumn))
			return $this->firstColumn;

		if($this->hasNameTable)
			return new Table_Column(1,
					'Name',
					'Name',
					'string',
					NULL);

		$resultArray = Database::Get()->SelectResultArray('
SELECT "ColumnName"."Name",
		"Column"."BackgroundName",
		"ColumnType"."Name" "ColumnType",
		"RelatedTable".id "RelatedTable"
	FROM "pertyler"."Table_Column" "Column"
		JOIN "pertyler"."Column_name" "ColumnName" ON "Column".id = "ColumnName"."Column"
				AND "ColumnName"."Language" = ' . Role::Select()->DefaultLanguage()->Id() . '
		LEFT JOIN pertyler."ColumnType" ON "Column"."ColumnType" = "ColumnType".id
		JOIN pg_catalog.pg_attribute ON pg_attribute.attrelid = (SELECT pg_class.oid
				FROM pg_catalog.pg_class
					JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
				WHERE pg_class.relkind IN (\'r\',
						\'v\')
						AND pg_namespace.nspname = \'' . $this->Schema() . '\'
						AND pg_class.relname = \'' . $this->backgroundName . '\')
				AND pg_attribute.attname = "Column"."BackgroundName"
			LEFT JOIN pg_catalog.pg_constraint ON pg_constraint.conrelid = pg_attribute.attrelid
					AND pg_constraint.conkey = ARRAY[pg_attribute.attnum]
				LEFT JOIN pertyler."Table_Table" "RelatedTable" ON regexp_replace("RelatedTable"."BackgroundName",
								\'[_][0-9]+\',
								\'\') = (SELECT relname
							FROM pg_catalog.pg_class
							WHERE relkind IN (\'r\',
									\'v\')
									AND oid = pg_constraint.confrelid)
	WHERE "Column"."Table" = ' . $this->id . '
			AND "Column"."Priority" = 1');

		if(!$resultArray)
			throw new Database_exception('Table ' . $this . ' has no name column.');

		if($resultArray['RelatedTable'])
			$relatedTable = Table::Select($resultArray['RelatedTable']);
		else
			$relatedTable = NULL;

		$this->firstColumn = new Table_Column(1,
				$resultArray['Name'],
				$resultArray['BackgroundName'],
				$resultArray['ColumnType'],
				$relatedTable);

		return $this->firstColumn;
	}

	private $columnArray;

	public function SelectColumnArray()
	{
		if(isset($this->columnArray))
			return $this->columnArray;

		if($this->hasNameTable)
			$this->columnArray[1] = $this->SelectFirstColumn();

		$resultArrayArray = Database::Get()->SelectResultArrayArray('
SELECT "Column"."Priority",
		"ColumnName"."Name",
		"Column"."BackgroundName",
		"ColumnType"."Name" "ColumnType",
		"RelatedTable".id "RelatedTable"
	FROM "pertyler"."Table_Column" "Column"
		JOIN "pertyler"."Column_name" "ColumnName" ON "Column".id = "ColumnName"."Column"
				AND "ColumnName"."Language" = ' . Role::Select()->DefaultLanguage()->Id() . '
		LEFT JOIN pertyler."ColumnType" ON "Column"."ColumnType" = "ColumnType".id
		JOIN pg_catalog.pg_attribute ON pg_attribute.attrelid = (SELECT pg_class.oid
				FROM pg_catalog.pg_class
					JOIN pg_catalog.pg_namespace  ON pg_namespace.oid = pg_class.relnamespace
				WHERE pg_class.relkind IN (\'r\',
						\'v\')
						AND pg_namespace.nspname = \'' . $this->Schema() . '\'
						AND pg_class.relname = \'' . $this->backgroundName . '\')
				AND pg_attribute.attname = "Column"."BackgroundName"
			LEFT JOIN pg_catalog.pg_constraint ON pg_constraint.conrelid = pg_attribute.attrelid
					AND pg_constraint.conkey = ARRAY[pg_attribute.attnum]
				LEFT JOIN pertyler."Table_Table" "RelatedTable" ON regexp_replace("RelatedTable"."BackgroundName",
								\'[_][0-9]+\',
								\'\')= (SELECT relname
							FROM pg_catalog.pg_class
							WHERE relkind IN (\'r\',
									\'v\')
									AND oid = pg_constraint.confrelid)
	WHERE "Column"."Table" = ' . $this->id);

		foreach($resultArrayArray AS $resultArray)
		{
			if(isset($resultArray['RelatedTable']))
				$relatedTable = Table::Select($resultArray['RelatedTable']);
			else
				$relatedTable = NULL;

			$this->columnArray[$resultArray['Priority']] = new Table_Column($resultArray['Priority'],
					$resultArray['Name'],
					$resultArray['BackgroundName'],
					$resultArray['ColumnType'],
					$relatedTable);
		}

		if($this->columnArray)
			return $this->columnArray;

		throw new Database_exception('Table ' . $this . ' has no name column.');
	}

	public function SelectRowsTableArray(Table_Row $row)
	{
		$tableArray = array();

		foreach($this->SelectTableArray() AS $table)
			$tableArray[] = $table->RowsTable($row);

		return $tableArray;
	}

	private $groupColumnArray;

	public function SelectGroupColumnArray()
	{
		if(empty($this->groupColumnArray))
		{
			$this->groupColumnArray = array();

			$query = '
SELECT "Column".id, "ColumnName"."Name", "Column"."BackgroundName", "Column"."Priority"
	FROM "pertyler"."Table_Column" "Column"
		JOIN "pertyler"."Column_name" "ColumnName" ON "Column".id = "ColumnName"."Column"
				AND "ColumnName"."Language" = ' . Role::Select()->DefaultLanguage()->Id() . '
		JOIN pertyler."ColumnType" ON "Column"."ColumnType" = "ColumnType".id
				AND "ColumnType"."Name" = \'group\'
	WHERE "Column"."Table" = ' . $this->id . '
	ORDER BY "Column"."Priority"';

			$resultArrayArray = Database::Get()->SelectResultArrayArray($query);

			if($resultArrayArray)
				foreach($resultArrayArray AS $resultArray)
					$this->groupColumnArray[$resultArray['Priority']] = new Table_GroupColumn($resultArray['Priority'],
							$resultArray['Name'],
							$resultArray['BackgroundName'],
							'group',
							NULL);

		}

		return $this->groupColumnArray;
	}

	private $privilegeArrayArray;

	public function SelectPrivilege($privilegeType,
			Language $language = NULL)
	{
		if(empty($this->privilegeArrayArray))
			$this->SelectPrivilegeArrayArray();

		if($language)
		{
			if(isset($this->privilegeArrayArray[$privilegeType][$language->Id()]))
				return $this->privilegeArrayArray[$privilegeType][$language->Id()];
		}
		else
		{
			if(isset($this->privilegeArrayArray[$privilegeType][Role::Select()->DefaultLanguage()->Id()]))
				return $this->privilegeArrayArray[$privilegeType][Role::Select()->DefaultLanguage()->Id()];

				if(isset($this->privilegeArrayArray[$privilegeType]))
					return current($this->privilegeArrayArray[$privilegeType]);
		}
	}

	public function SelectPrivilegeArray($privilegeType = NULL)
	{
		if(empty($this->privilegeArrayArray))
			$this->SelectPrivilegeArrayArray();

		if($privilegeType)
		{
			if(isset($this->privilegeArrayArray[$privilegeType]))
				return $this->privilegeArrayArray[$privilegeType];

			return array();
		}

		return $this->privilegeArrayArray;
	}

	private function selectPrivilegeArrayArray()
	{
		if(empty($this->privilegeArray))
		{
			$this->privilegeArray = array();

			$resultArrayArray = Database::Get()->SelectResultArrayArray('
SELECT "Privilege".id, "PrivilegeType"."Name" "PrivilegeType", "Privilege"."Language"
	FROM pertyler."Table_Privilege" "Privilege"
		JOIN pertyler."PrivilegeType" ON "Privilege"."PrivilegeType" = "PrivilegeType".id
	WHERE "Privilege"."Table" = ' . $this->id);

			if($resultArrayArray)
				foreach($resultArrayArray AS $resultArray)
					$this->privilegeArrayArray[$resultArray['PrivilegeType']][$resultArray['Language']] = new Table_Privilege($this,
							$resultArray['id'],
							$resultArray['PrivilegeType'],
							Language::Select($resultArray['Language']));
		}

		return $this->privilegeArrayArray;
	}

	private function privilegedLanguageIdArray()
	{
		$privilegedLanguageIdArray = array();

		$privilegeArray = $this->SelectPrivilegeArray('select');

		require_once __DIR__ . '/Role.php';

		foreach($privilegeArray AS $privilege)
			if(Role::Select()->SelectRolePrivilege($privilege))
				$privilegedLanguageIdArray[] = $privilege->Language()->Id();

		return $privilegedLanguageIdArray;
	}

	private function sQLGeneratorTable()
	{
		$columnArray[1] = $this->selectFirstColumn()->BackgroundName();

		if($this->HasUnpublishedColumn())
			$columnArray[2] = 'Unpublished';

		if($this->selectFirstColumn()->RelatedTable())
		{
			require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/IndicativeTable.php';

			return new \Pert\PostgreSQLGenerator\IndicativeTable($this->backgroundName,
					$this->Schema(),
					$columnArray,
					$this->selectFirstColumn()->RelatedTable()->sQLGeneratorTable());
		}

		if($this->hasNameTable)
		{
			require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/LingualNamedTable.php';

			return new \Pert\PostgreSQLGenerator\LingualNamedTable($this->backgroundName,
					$this->Schema(),
					$columnArray,
					$this->privilegedLanguageIdArray(),
					$this->hasNameTableAlternativeColumn);
		}

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Table.php';

		$sQLGeneratorTable = new \Pert\PostgreSQLGenerator\Table($this->backgroundName,
					$this->Schema(),
					$columnArray);

		if($this->hasLanguage)
		{
			require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/ArrayCondition.php';

			require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/ArrayInput.php';

			$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\ArrayCondition('Language',
					new \Pert\PostgreSQLGenerator\ArrayInput($this->privilegedLanguageIdArray())));
		}

		return $sQLGeneratorTable;
	}

	protected function withParentPostgreSQLGeneratorTable()
	{
		if($this->SelectParentTable())
			return $this->SelectParentTable()->withParentPostgreSQLGeneratorTable()->AddChild($this->sQLGeneratorTable());

		return $this->sQLGeneratorTable();
	}

	public function SelectRow($id)
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$sQLGeneratorTable = $this->withParentPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Condition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Input.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\Condition('id',
				new \Pert\PostgreSQLGenerator\Input($id)));

		try
		{
			$resultArray = Database::Get()->SelectResultArray($sQLGeneratorTable->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if($resultArray)
		{
			if(isset($resultArray['Published']))
			{
				require_once __DIR__ . '/UnpublishedRow.php';

				if(!$resultArray['Published'])
					return new UnpublishedRow($this,
							$resultArray['id'],
							$resultArray['Name']);
			}

			require_once __DIR__ . '/PublishedRow.php';

			return new PublishedRow($this,
					$resultArray['id'],
					$resultArray['Name']);
		}
	}

	public function SelectRowArray(Array $idArray)
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$sQLGeneratorTable = $this->withParentPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/ArrayCondition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/ArrayInput.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\ArrayCondition('id',
				new \Pert\PostgreSQLGenerator\ArrayInput($idArray)));

		try
		{
			$resultArrayArray = Database::Get()->SelectResultArrayArray($sQLGeneratorTable->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if(!$resultArrayArray)
			return array();

		require_once __DIR__ . '/PublishedRow.php';

		require_once __DIR__ . '/UnpublishedRow.php';

		foreach($resultArrayArray AS $resultArray)
			if((empty($resultArray['Published'])) OR ($resultArray['Published']))
				$rowArray[$resultArray['id']] = new PublishedRow($this,
						$resultArray['id'],
						$resultArray['Name']);
			else
				$rowArray[$resultArray['id']] = new UnpublishedRow($this,
						$resultArray['id'],
						$resultArray['Name']);

		return $rowArray;
	}

	public function SelectUnpublishedRowArray()
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		if(!$this->HasUnpublishedColumn())
			throw new Database_exception('No unpublished column.');

		$sQLGeneratorTable = $this->withParentPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Condition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Input.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\Condition('Unpublished',
				new \Pert\PostgreSQLGenerator\Input(true)));

		try
		{
			$resultArrayArray = Database::Get()->SelectResultArrayArray($sQLGeneratorTable->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if(!$resultArrayArray)
			return array();

		require_once __DIR__ . '/UnpublishedRow.php';

		foreach($resultArrayArray AS $resultArray)
			$rowArray[] = new UnpublishedRow($this,
					$resultArray['id'],
					$resultArray['Name']);

		return $rowArray;
	}

	public function SelectRowsParentRow(Table_Row $row)
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		if(!($parentTable = $this->SelectParentTable()))
			throw new Database_exception('No parent table.');

		$sQLGeneratorTable = $this->withParentPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Condition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Input.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\Condition('id',
				new \Pert\PostgreSQLGenerator\Input($row->Id())));

		try
		{
			$resultArray = Database::Get()->SelectResultArray($sQLGeneratorTable->GetParent()->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if($resultArray)
		{
			if(isset($resultArray['Published']))
				if(!$resultArray['Published'])
				{
					require_once __DIR__ . '/PublishedRow.php';

					return new UnpublishedRow($parentTable,
							$resultArray['id'],
							$resultArray['Name']);
				}

			require_once __DIR__ . '/UnpublishedRow.php';

			return new PublishedRow($parentTable,
					$resultArray['id'],
					$resultArray['Name']);
		}
	}

	private function publishedPostgreSQLGeneratorTable()
	{
		$sQLGeneratorTable = $this->sQLGeneratorTable();

		if($this->HasUnpublishedColumn())
		{
			require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Condition.php';

			require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Input.php';

			$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\Condition('Unpublished',
					new \Pert\PostgreSQLGenerator\Input(false)));
		}

		return $sQLGeneratorTable;
	}

	protected function withParentPublishedPostgreSQLGeneratorTable()
	{
		if($this->SelectParentTable())
			return $this->SelectParentTable()->withParentPublishedPostgreSQLGeneratorTable()->AddChild($this->publishedPostgreSQLGeneratorTable());

		return $this->publishedPostgreSQLGeneratorTable();
	}

	public function SelectPublishedRowArray()
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		try
		{
			$resultArrayArray = Database::Get()->SelectResultArrayArray($this->withParentPublishedPostgreSQLGeneratorTable()->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if(!$resultArrayArray)
			return array();

		require_once __DIR__ . '/PublishedRow.php';

		foreach($resultArrayArray AS $resultArray)
			$rowArray[] = new PublishedRow($this,
					$resultArray['id'],
					$resultArray['Name']);

		return $rowArray;
	}

	public function SelectRelatedPublishedRowArray(Table_Row $row,
			Table_Column $column)
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$sQLGeneratorTable = $this->withParentPublishedPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Condition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Input.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\Condition($column->BackgroundName(),
				new \Pert\PostgreSQLGenerator\Input($row->Id())));

		try
		{
			$resultArrayArray = Database::Get()->SelectResultArrayArray($sQLGeneratorTable->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if(!$resultArrayArray)
			return array();

		require_once __DIR__ . '/PublishedRow.php';

		foreach($resultArrayArray AS $resultArray)
			$rowArray[] = new PublishedRow($this,
					$resultArray['id'],
					$resultArray['Name']);

		return $rowArray;
	}

	public function SelectSearchedPublishedRowArray(Array $columnValueArray)
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this . '.');

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$sQLGeneratorTable = $this->withParentPublishedPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/LikeStringCondition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Input.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/ArrayCondition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/ArrayInput.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/NullCondition.php';

		foreach($columnValueArray AS $columnValue)
			if($columnValue->Column()->String())
				$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\LikeStringCondition($columnValue->Column()->BackgroundName(),
						new \Pert\PostgreSQLGenerator\Input($columnValue->Value())));
			elseif($columnValue->Column()->RelatedTable())
			{
				if($columnValue->Value())
					foreach($columnValue->Value() AS $row)
						$rowIdArray[] = $row->Id();

				if(isset($rowIdArray))
					$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\ArrayCondition($columnValue->Column()->BackgroundName(),
							new \Pert\PostgreSQLGenerator\ArrayInput($rowIdArray)));
				else
					$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\NullCondition($columnValue->Column()->BackgroundName()));
			}


		try
		{
			$resultArrayArray = Database::Get()->SelectResultArrayArray($sQLGeneratorTable->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if(!$resultArrayArray)
			return array();

		require_once __DIR__ . '/PublishedRow.php';

		foreach($resultArrayArray AS $resultArray)
			$rowArray[] = new PublishedRow($this,
					$resultArray['id'],
					$resultArray['Name']);

		return $rowArray;
	}

	public function SelectRowsGroupPublishedRowArray(Table_Row $row,
			Row_GroupColumnValue $groupColumnValue)
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$sQLGeneratorTable = $this->withParentPublishedPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/OppositeStringCondition.php';

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Input.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\OppositeStringCondition('id',
				new \Pert\PostgreSQLGenerator\Input($row->Id())));

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/Condition.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\Condition($groupColumnValue->Column()->BackgroundName(),
				new \Pert\PostgreSQLGenerator\Input($groupColumnValue->Value())));

		try
		{
			$resultArrayArray = Database::Get()->SelectResultArrayArray($sQLGeneratorTable->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if(!$resultArrayArray)
			return array();

		require_once __DIR__ . '/PublishedRow.php';

		foreach($resultArrayArray AS $resultArray)
			$rowArray[] = new PublishedRow($this,
					$resultArray['id'],
					$resultArray['Name']);

		return $rowArray;
	}

	public function SelectGrouplessRowArray(Table_GroupColumn $column)
	{
		if(!($privilege = $this->SelectPrivilege('select')))
			throw new Database_exception('No privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$sQLGeneratorTable = $this->withParentPublishedPostgreSQLGeneratorTable();

		require_once __DIR__ . '/../library/Pert/PostgreSQLGenerator/NullCondition.php';

		$sQLGeneratorTable->AddCondition(new \Pert\PostgreSQLGenerator\NullCondition($column->BackgroundName()));

		try
		{
			$resultArrayArray = Database::Get()->SelectResultArrayArray($sQLGeneratorTable->SelectSQL());
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if(!$resultArrayArray)
			return array();

		require_once __DIR__ . '/PublishedRow.php';

		foreach($resultArrayArray AS $resultArray)
			$rowArray[] = new PublishedRow($this,
					$resultArray['id'],
					$resultArray['Name']);

		return $rowArray;
	}

	public function SelectUnapprovedPublishedRowArray()
	{
		if(!($privilege = $this->SelectPrivilege('approve')))
			throw new Database_exception('No approve privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		try
		{
			$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "idArray"
	FROM "' . $this->Schema() . '"."' . $this->backgroundName . '"
	WHERE id::text !~ \'[^0-9]\'
			AND EXISTS(SELECT true
						FROM pertyler."Table_ChangeLog"
						WHERE id  = (SELECT max(id)
									FROM pertyler."Table_ChangeLog"
									WHERE "Table" = ' . $this->id . '
											AND "Row" = "' . $this->backgroundName . '".id::int)
								AND "PrivilegeType" = 4)');
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if($resultArray['idArray'])
			return $this->SelectRowArray($resultArray['idArray']);
	}

	public function SelectNonexistentPublishedRowArray(PublishedRow_Table $table)
	{
		if(!($privilege = $this->SelectPrivilege('approve')))
			throw new Database_exception('No approve privilege for table ' . $this->Id());

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		try
		{
			$resultArray = Database::Get()->SelectResultArray('
SELECT array_agg(id) "idArray"
	FROM "' . $this->Schema() . '"."' . $this->backgroundName . '"
	WHERE id::text !~ \'[^0-9]\'
			AND NOT EXISTS(SELECT true
						FROM "' . $table->Schema() . '"."' . $table->backgroundName . '"
						WHERE "' . $this->UniqueName() . '"  = "' . $this->backgroundName . '".id
								AND "' . $table->SelectParentTable()->UniqueName() . '" = ' . $table->Parent()->Id() . ')');
		}
		catch(Database_exception $e)
		{
			throw new Database_exception('Wrong SQL for table "' . $this->UniqueName() . '".');
		}

		if($resultArray['idArray'])
			return $this->SelectRowArray($resultArray['idArray']);
	}

	public function InsertRow(Array $inputColumnArray)
	{
		if(!($privilege = $this->SelectPrivilege('insert')))
			throw new Database_exception('No ' . $privilage . ' privilege');

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$columnArray = $this->SelectColumnArray();

		if($this->hasNameTable)
			unset($columnArray[1]);

		Database::Get()->UpdateTransactionBegin();

		$query = '
INSERT INTO "' . $this->Schema() . '"."' . $this->backgroundName . '" (id';

		foreach($columnArray AS $column)
		{
			if($column->BackgroundName() == 'Language')
				$this->hasLanguage = false;

			if((($column->ColumnType() == 'dropdown') OR ($column->ColumnType() == 'integer') OR ($column->ColumnType() == 'text') OR ($column->ColumnType() == 'paragraph') OR ($column->ColumnType() == 'string') OR ($column->ColumnType() == 'date') OR ($column->ColumnType() == 'boolean') OR ($column->ColumnType() == 'float')) AND (isset($inputColumnArray[$column->Priority()])))
				$query .= ',
		"' . $column->BackgroundName() . '"';
		}

		if($this->hasLanguage)
			$query .= ',
		"Language"';

		$query .= ')
	VALUES (DEFAULT';

		foreach($columnArray AS $column)
			if((($column->ColumnType() == 'dropdown') OR ($column->ColumnType() == 'integer') OR ($column->ColumnType() == 'text') OR ($column->ColumnType() == 'paragraph') OR ($column->ColumnType() == 'string') OR ($column->ColumnType() == 'date') OR ($column->ColumnType() == 'boolean') OR ($column->ColumnType() == 'float')) AND (isset($inputColumnArray[$column->Priority()])))
				if($column->ColumnType() == 'dropdown')
					$query .= ',
			' . $inputColumnArray[$column->Priority()]->Id();
				elseif(($column->ColumnType() == 'integer') OR ($column->ColumnType() == 'string') OR ($column->ColumnType() == 'text') OR ($column->ColumnType() == 'paragraph') OR ($column->ColumnType() == 'date') OR ($column->ColumnType() == 'boolean') OR ($column->ColumnType() == 'float'))
					$query .= ',
			' . Database::Get()->SelectInput($inputColumnArray[$column->Priority()]);

		if($this->hasLanguage)
			$query .= ', ' . Role::Select()->DefaultLanguage()->Id();

		$query .= ')
	RETURNING id';

		try
		{
			$id = Database::Get()->SelectResult($query);

			if($this->hasNameTable)
			{
				$nameid = Database::Get()->SelectResult('SELECT nextval(\'"' . $this->Schema() . '"."' . $this->UniqueName() . 'Name_id"\'::regclass)');

				Database::Get()->Update('
INSERT INTO "' . $this->Schema() . '"."' . $this->UniqueName() . '_name" ("' . $this->UniqueName() . '",
		id,
		"Language",
		"Name")
	VALUES (' . $id . ',
			' . $nameid . ',
			' . Role::Select()->DefaultLanguage()->Id() . ',
			' . Database::Get()->SelectInput($inputColumnArray[1]) . ')');
			}
		}
		catch(Database_exception $e)
		{
			Database::Get()->UpdateTransactionRollback();

			throw new Database_exception('Wrong SQL for inserting into table "' . $this . '"');
		}

		Role_Moderator::Select()->InsertChangeLog($privilege,
				$id);

		Database::Get()->UpdateTransactionCommit();

		return $this->SelectRow($id);
	}

	private function deleteChildUnpublishedRow(Table_Row $row)
	{
		foreach($this->selectChildUnpublishedArray() AS $table)
		{
			Database::Get()->Update('
DELETE
	FROM "' . $table->Schema() . '"."' . $table->backgroundName . '"
	WHERE "' . $this->UniqueName() . '" = \'' . $row->Id() . '\'
			AND "Unpublished" = true');
		}

		return true;
	}

	private function updateNullRelatedUnpublishedRow(Table_Row $row)
	{
		foreach($this->selectNullRelatedUnpublishedArray() AS $table)
			foreach($table->selectColumnArray() AS $column)
				if($column->RelatedTable())
					if($column->RelatedTable()->Id() == $this->Id())
					{
						Database::Get()->Update('
DELETE
	FROM "' . $table->Schema() . '"."' . $table->backgroundName . '"
	WHERE "' . $column->BackgroundName() . '" = \'' . $row->Id() . '\'
			AND "Unpublished" = true');
					}

		return true;
	}

	private function deleteNotNullRelatedUnpublishedRow(Table_Row $row)
	{
		foreach($this->selectNotNullRelatedUnpublishedArray() AS $table)
			foreach($table->selectColumnArray() AS $column)
				if($column->RelatedTable())
					if($column->RelatedTable()->Id() == $this->Id())
					{
						Database::Get()->Update('
DELETE
	FROM "' . $table->Schema() . '"."' . $table->backgroundName . '"
	WHERE "' . $column->BackgroundName() . '" = \'' . $row->Id() . '\'
			AND "Unpublished" = true');
					}

		return true;
	}
}

require_once __DIR__ . '/aPrivilege.php';

class Table_Privilege extends aPrivilege
{
}

require_once __DIR__ . '/aColumn.php';

class Table_Column extends aColumn
{
}

class Table_GroupColumn extends Table_Column
{
}

require_once __DIR__ . '/aRow.php';

class Table_Row extends aRow
{
	public function SelectColumnValueArray()
	{
		$columnArray = $this->table->SelectColumnArray();

		if($this->table->HasNameTable())
		{
			$columnValueArray[1] = new Row_ColumnValue($columnArray[1],
					$this->__toString());

			unset($columnArray[1]);
		}

		if($columnArray)
		{
			$id = 0;

			foreach($columnArray AS $column)
			{
				if($id++)
					$query .= ',
		';
				else
					$query = '
SELECT ';

				$query .= '"' . $column->BackgroundName() . '"';
			}

			$query .= '
	FROM "' . $this->table->Schema() . '"."' . $this->table->BackgroundName() . '"
	WHERE id = ' . Database::Get()->SelectInput($this->Id());

			$resultArray = Database::Get()->SelectResultArray($query);

			foreach($columnArray AS $column)
				if(isset($resultArray[$column->BackgroundName()]))
					if($column->RelatedTable())
						$columnValueArray[$column->Priority()] = new Row_ColumnValue($column,
								$column->RelatedTable()->SelectRow($resultArray[$column->BackgroundName()]));
					else
						$columnValueArray[$column->Priority()] = new Row_ColumnValue($column,
								$resultArray[$column->BackgroundName()]);
				else
					$columnValueArray[$column->Priority()] = new Row_ColumnValue($column,
							null);
		}

		return $columnValueArray;
	}

	public function SelectGroupColumnValueArray()
	{
		$columnArray = $this->table->SelectGroupColumnArray();

		$groupColumnValueArray = array();

		if($columnArray)
		{
			$id = 0;

			foreach($columnArray AS $column)
			{
				if($id++)
					$query .= ', ';
				else
					$query = '
SELECT ';

				$query .= '"' . $column->BackgroundName() . '"';
			}

			$query .= '
FROM "' . $this->table->Schema() . '"."' . $this->table->BackgroundName() . '"
WHERE id = ' . $this->Id();

			$resultArray = Database::Get()->SelectResultArray($query);

			foreach($columnArray AS $column)
				if(isset($resultArray[$column->BackgroundName()]))
					$groupColumnValueArray[$column->Priority()] = new Row_GroupColumnValue($column,
							$resultArray[$column->BackgroundName()]);
				else
					$groupColumnValueArray[$column->Priority()] = new Row_GroupColumnValue($column,
							null);
		}

		return $groupColumnValueArray;
	}

	public function SelectLastChangeLog()
	{
		if($resultArray = Database::Get()->SelectResultArray('
SELECT max(id) "ChangeLog"
	FROM pertyler."Table_ChangeLog"
	WHERE "Table" = ' . $this->table->Id() . '
			AND "Row" = ' . $this->Id()))
			return Row_ChangeLog::Select($resultArray['ChangeLog']);
	}

	public function Update(Array $inputColumnArray)
	{
		if(!($privilege = $this->table->SelectPrivilege('update')))
			throw new Database_exception('No ' . $privilage . ' privilege');

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		$changed = false;

		$columnArray = $this->table->SelectRowsColumnArray($this);

		if($this->table->HasNameTable())
		{
			if((isset($inputColumnArray[1])) AND ($columnArray[1]->Value() != $inputColumnArray[1]))
			{
				$query = '
UPDATE "' . $this->table->Schema() . '"."' . $this->table->UniqueName() . '_name"
	SET "Name" = ' . Database::Get()->SelectInput($inputColumnArray[1]) . '
	WHERE "' . $this->table->UniqueName() . '" = ' . Database::Get()->SelectInput($this->Id()) . '
			AND "Language" = ' . Role::Select()->DefaultLanguage()->Id();

				if($this->table->HasNameTableAlternativeColumn())
					$query .= '
			AND "Alternative" = false';

				try
				{
					Database::Get()->Update($query);
				}
				catch(Database_exception $e)
				{
					Database::Get()->UpdateTransactionRollback();

					throw new Database_exception('Wrong SQL for update table "' . $this->table . '"');
				}

				$this->ChangeName($inputColumnArray[1]);

				$changed = true;
			}

			unset($columnArray[1]);
		}

		$id = 0;

		$query = '
UPDATE "' . $this->table->Schema() . '"."' . $this->table->BackgroundName() . '"
	SET ';

		foreach($columnArray AS $column)
			if($column->ColumnType() == 'dropdown')
			{
				if(isset($inputColumnArray[$column->Priority()]))
				{
					if((!$column->Value()) OR ($column->Value()->Id() != $inputColumnArray[$column->Priority()]->Id()))
					{
						if($id++)
							$query .= ',
			';

						$query .= '"' . $column->BackgroundName() . '" = ' . $inputColumnArray[$column->Priority()]->Id();
					}
				}
				elseif($column->Value())
				{
					if($id++)
						$query .= ',
			';

					$query .= '"' . $column->BackgroundName() . '" = NULL';
				}
			}
			elseif((($column->ColumnType() == 'integer') OR ($column->ColumnType() == 'string') OR ($column->ColumnType() == 'text') OR ($column->ColumnType() == 'paragraph') OR ($column->ColumnType() == 'boolean') OR ($column->ColumnType() == 'float')) AND ($column->Value() != $inputColumnArray[$column->Priority()]))
			{
				if($id++)
					$query .= ',
			';

				$query .= '"' . $column->BackgroundName() . '" = ' . Database::Get()->SelectInput($inputColumnArray[$column->Priority()]);
			}
			elseif(($column->ColumnType() == 'date') AND (((!$column->Value()) AND ($inputColumnArray[$column->Priority()]))
OR (($column->Value()) AND ($inputColumnArray[$column->Priority()]) AND ($column->Value() != $inputColumnArray[$column->Priority()]))
OR (($column->Value()) AND (!$inputColumnArray[$column->Priority()]))))
			{
				if($id++)
					$query .= ',
			';

				$query .= '"' . $column->BackgroundName() . '" = ' . Database::Get()->SelectInput($inputColumnArray[$column->Priority()]);
			}

		$query .= '
	WHERE id = \'' . $this->Id() . '\'';

		if($id)
		{
			try
			{
				Database::Get()->Update($query);
			}
			catch(Database_exception $e)
			{
				Database::Get()->UpdateTransactionRollback();

				throw new Database_exception('Wrong SQL for update table "' . $this . '"');
			}

			$changed = true;
		}

		if($changed)
			Role_Moderator::Select()->InsertChangeLog($privilege,
					$this->Id());

		Database::Get()->UpdateTransactionCommit();

		return $changed;
	}

	public function UpdateAsApproved()
	{
		if(!($privilege = $this->table->SelectPrivilege('approve')))
			throw new Database_exception('No ' . $privilage . ' privilege');

		require_once __DIR__ . '/Role.php';

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		Role_Moderator::Select()->InsertChangeLog($privilege,
				$this->Id());
	}

	public function Delete()
	{
		if(!($privilege = $this->table->SelectPrivilege('delete')))
			throw new Database_exception('No ' . $privilage . ' privilege');

		if(!Role::Select()->SelectRolePrivilege($privilege))
			throw new RolePrivilege_exception($privilege);

		if($this->table->NameTable())
		{
			$columnValueArray = $this->SelectColumnValue();

			if($columnValueArray[2]->Column()->BackgroundName() == 'Alternative')
				if(!$columnValueArray[2]->Value())
					throw new Database_exception('Primary name cannot deleted.');
		}

		Database::Get()->UpdateTransactionBegin();

		try
		{
			if($this->table->hasNameTable)
				Database::Get()->Update('
DELETE FROM "' . $this->table->Schema() . '"."' . $this->table->UniqueName() . '_name"
	WHERE "' . $this->table->UniqueName() . '" = ' . $this->Id());

			$this->table->deleteChildUnpublishedRow($this);

			$this->table->updateNullRelatedUnpublishedRow($this);

			$this->table->deleteNotNullRelatedUnpublishedRow($this);

			Database::Get()->Update('
DELETE FROM "' . $this->table->Schema() . '"."' . $this->table->BackgroundName() . '" "' . $this->table->UniqueName() . '"
	WHERE "' . $this->table->UniqueName() . '".id = \'' . $this->Id() . '\'');
		}
		catch(Database_exception $e)
		{
			Database::Get()->UpdateTransactionRollback();

			throw new Database_exception('Row cannot deleted');
		}

		Role_Moderator::Select()->InsertChangeLog($privilege,
				$this->Id());

		Database::Get()->UpdateTransactionCommit();

		return true;
	}
}

require_once __DIR__ . '/aColumnValue.php';

class Row_ColumnValue extends aColumnValue
{
}

class Row_GroupColumnValue extends Row_ColumnValue
{
}

require_once __DIR__ . '/aChangeLog.php';

class Row_ChangeLog extends aChangeLog
{
	public static function Select($id)
	{
		if($resultArray = Database::Get()->SelectResultArray('
SELECT "ChangeLog"."Time",
		"Privilege"."PrivilegeType",
		"Moderator"."Name" "ModeratorName"
	FROM pertyler."Moderator_ChangeLog" "ChangeLog"
		JOIN pertyler."Table_Privilege" "Privilege" ON "Privilege".id = "ChangeLog"."Privilege"
		JOIN pertyler."Role_Moderator" "Moderator" ON "Moderator".id = "ChangeLog"."Moderator"
	WHERE "ChangeLog".id  = ' . Database::Get()->SelectInput($id)))
			return new self($resultArray['Time'],
					 $resultArray['PrivilegeType'],
					 $resultArray['ModeratorName']);
	}
}
